﻿#include "stdafx.h"
#include "PhysicsManager.h"
#include "PhysXObj.h"
#include "PhysTriggerReport.h"
#include "Stream.h"
#include "DebugAssert.h"

_NAMESPACE_BEGIN

PhysicsManager::PhysicsManager()
{
	gPhysicsSDK = NULL;
	pWorldScene = NULL;
}

PhysicsManager::~PhysicsManager()
{
	//GetPhysicsResults();  // Make sure to fetchResults() before shutting down
	
	if(pWorldScene)
		gPhysicsSDK->releaseScene(*pWorldScene);

	NxCloseCooking();
	if (gPhysicsSDK)  gPhysicsSDK->release();

	SAVE_LOG("物理引擎释放完毕");
}

void PhysicsManager::ObjectsUpdate()
{
	// 遍历所有物体给予物理更新
	// 物理物体的物理部分优先于图形部分，物理更新连带图形更新
	for (std::list<PhysXObj*>::iterator i=physObj.begin();i!=physObj.end();i++)
	{
		(*i)->Update();
	}
}

void PhysicsManager::AddObj( PhysXObj* obj )
{
	physObj.push_back(obj);
}

void PhysicsManager::RemoveObj( PhysXObj* obj )
{
	std::list<PhysXObj*>::iterator f=find(physObj.begin(),physObj.end(),obj);
	physObj.erase(f);
}

void PhysicsManager::InitialNx(NxSceneDesc& sceneDesc)
{
	gPhysicsSDK = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION);
	if (!gPhysicsSDK)  return;

	NxInitCooking();

	gPhysicsSDK->setParameter(NX_SKIN_WIDTH, 0.01);

	sceneDesc.simType				= NX_SIMULATION_SW;
	pWorldScene = gPhysicsSDK->createScene(sceneDesc);	
	assert(pWorldScene);

	SetSpeed(3.0f);

	NxMaterial* defaultMaterial=pWorldScene->getMaterialFromIndex(0); 
	defaultMaterial->setRestitution(0.1f);
	defaultMaterial->setStaticFriction(0.5f);
	defaultMaterial->setDynamicFriction(0.5f);

	pWorldScene->setUserTriggerReport(TriggerReport::Instance());

	// 第一帧物理仿真
	StartPhysics(0);	

	SAVE_LOG("PhysX物理引擎初始化成功");
}

void PhysicsManager::StartPhysics( float worldtime )
{
	if(pWorldScene)
	{
		pWorldScene->simulate(UPDATE_PS);
		pWorldScene->flushStream();
	}
}

void PhysicsManager::Update()
{
	GetPhysicsResults();
	
	StartPhysics(simulateTime);	
	simulateTime=max(0.0,worldClock.GetElapse())*speedRate;
	worldClock.Start();

	ObjectsUpdate();
}

void PhysicsManager::GetPhysicsResults()
{
	int times=0;
	while (!pWorldScene->fetchResults(NX_RIGID_BODY_FINISHED, true))
		assert(times++<100000);
}

void PhysicsManager::ConnectToRemoteDebuger()
{
	SAVE_LOG("连接物理调试器");
	gPhysicsSDK->getFoundationSDK().getRemoteDebugger()->connect ("localhost", 5425);
}

NxScene* PhysicsManager::GetWorldScene()
{
	return pWorldScene;
}

void PhysicsManager::LoadPhysMesh( CONST_REF(std::string)fileName, CONST_REF(std::string)name , CONST_REF(NxVec3)pos)
{
	FILE* fp = fopen(fileName.c_str(), "rb");
	if (!fp)
	{
		SAVE_LOG("加载文件" + fileName + "失败");
		assert(!"加载文件失败");
	}

	SAVE_LOG("----------------加载物理模型----------------");

	SAVE_LOG("模型文件名：");
	SAVE_LOG(fileName);

	NxVec3* vertex = NULL;
	NxU16*  index = NULL;
	int vertexNum = 0;
	int triangleNum = 0;
	int readDataNum = 0;
	
	//读取多边形数
	readDataNum = fread(&triangleNum,sizeof(int),1,fp);
	assert(readDataNum == 1);

	//读取顶点数
	readDataNum = fread(&vertexNum,sizeof(int),1,fp);
	assert(readDataNum == 1);

	vertex = new NxVec3[vertexNum];
	index = new NxU16[triangleNum*3];

	//读取顶点索引
	fread(index,sizeof(NxU16),triangleNum*3,fp);

	//读取顶点位置
	fread(vertex,sizeof(NxVec3),vertexNum,fp);

	SAVE_LOG("模型多边形数：");
	SAVE_LOG(triangleNum);
	SAVE_LOG("模型顶点数：");
	SAVE_LOG(vertexNum);
	SAVE_LOG("模型位置：");
	std::string posStr;
	posStr += boost::lexical_cast<std::string>(pos.x);
	posStr += ",";
	posStr += boost::lexical_cast<std::string>(pos.y);
	posStr += ",";
	posStr += boost::lexical_cast<std::string>(pos.z);
	SAVE_LOG(posStr);


	//创建物理模型

	NxTriangleMeshDesc TriMeshDesc;
	TriMeshDesc.numVertices = vertexNum;
	TriMeshDesc.numTriangles = triangleNum;
	TriMeshDesc.pointStrideBytes = sizeof(NxVec3);
	TriMeshDesc.triangleStrideBytes = 3*sizeof(NxU16);
	TriMeshDesc.points = vertex;
	TriMeshDesc.triangles = index;
	TriMeshDesc.flags = NX_MF_16_BIT_INDICES;

	NxTriangleMeshShapeDesc ShapeDesc;
	//NxInitCooking();

	// Cooking from memory
	MemoryWriteBuffer buf;
	bool status = NxCookTriangleMesh(TriMeshDesc, buf);
	assert(status);
	ShapeDesc.meshData = gPhysicsSDK->createTriangleMesh(MemoryReadBuffer(buf.data));

	//ShapeDesc.materialIndex = world->defaultMaterial->getMaterialIndex();

	NxActorDesc actorDesc;
	actorDesc.shapes.pushBack(&ShapeDesc);
	actorDesc.globalPose.t = pos;

	//LPCWSTR perm = _towchar(name.c_str(), false);
	//actorDesc.name = _tochar(perm, false);
	//actorDesc.userData = NULL;
	//actorDesc.userData = (void*)1;
	NxActor* act = pWorldScene->createActor(actorDesc);
	
	assert(act);

	physMeshTable[name] = act;

	delete[]	index;
	delete[]	vertex;

	fclose(fp);

	SAVE_LOG("----------------加载模型成功----------------");
}

NxActor* PhysicsManager::GetMeshActor( CONST_REF(std::string)name )
{
	return physMeshTable[name];
}

_NAMESPACE_END